﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Day1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("TPL operation!!!");
            // demo1();
            // demo2();
            // demo3();
            // demo4();
            // demo5();
            // demo6();
            demo7();
        }

        #region demo1
        /// <summary>
        /// Parallel.Invoke尽可能多的执行提供的每一个操作
        /// </summary>
        private static void demo1()
        {
            // 测量运行时间
            Stopwatch stopwatch = new Stopwatch();
            Console.WriteLine("Normal:");
            stopwatch.Start();
            RunOne();
            RunTwo();
            stopwatch.Stop();
            Console.WriteLine("Normal cost:" + stopwatch.ElapsedMilliseconds + " milliseconds");
            Console.WriteLine("-------------------------------------------");
            Console.WriteLine("Parallel:");
            stopwatch.Restart();
            Parallel.Invoke(RunOne, RunTwo);
            stopwatch.Stop();
            Console.WriteLine("Parallel cost:" + stopwatch.ElapsedMilliseconds + " milliseconds");
        }

        private static void RunTwo()
        {
            Thread.Sleep(3000);
            Console.WriteLine("The RunTwo cost 3 second");
        }

        private static void RunOne()
        {
            Thread.Sleep(2000);
            Console.WriteLine("The RunOne cost 2 second");
        }
        #endregion

        #region demo2
        /// <summary>
        /// Parallel.For执行for循环，其中可能并行执行迭代
        /// </summary>
        private static void demo2()
        {
            Stopwatch stopwatch = new Stopwatch();
            Console.WriteLine("Normal:");
            stopwatch.Start();
            for(int i = 0; i < 10000; i++)
            {
                for (int j = 0; j < 60000; j++)
                {
                    int sum = 0;
                    sum += i;
                }
            }
            stopwatch.Stop();
            Console.WriteLine("Normal cost:" + stopwatch.ElapsedMilliseconds + " milliseconds");
            Console.WriteLine("-------------------------------------------");
            Console.WriteLine("Parallel:");
            stopwatch.Restart();
            Parallel.For(0, 10000, (i) => {
                for (int j = 0; j < 60000; j++)
                {
                    int sum = 0;
                    sum += i;
                }
            });
            stopwatch.Stop();
            Console.WriteLine("Parallel cost:" + stopwatch.ElapsedMilliseconds + " milliseconds");
        }
        #endregion

        #region demo3
        /// <summary>
        /// Parallel.For循环耗时长的情况
        /// Parallel.For由于是并行运行的，所以会同时访问全局变量sum,为了得到正确的结果，要加锁
        /// </summary>
        private static void demo3()
        {
            object o = new object();
            long sum = 0;
            Stopwatch stopwatch = new Stopwatch();
            Console.WriteLine("Normal:");
            stopwatch.Start();
            for (int i = 0; i < 10000; i++)
            {
                for (int j = 0; j < 60000; j++)
                {
                    sum++;
                }
            }
            stopwatch.Stop();
            Console.WriteLine("Normal cost:" + stopwatch.ElapsedMilliseconds + " milliseconds");
            Console.WriteLine("-------------------------------------------");
            Console.WriteLine("Parallel:");
            stopwatch.Restart();
            Parallel.For(0, 10000, (i) => {
                for (int j = 0; j < 60000; j++)
                {
                    lock (o)
                    {
                        sum++;
                    }
                }
            });
            stopwatch.Stop();
            Console.WriteLine("Parallel cost:" + stopwatch.ElapsedMilliseconds + " milliseconds");
        }
        #endregion

        #region demo4
        /// <summary>
        /// 并行测试
        /// </summary>
        private static void demo4()
        {
            Parallel.For(0, 100, (i) => {
                Console.WriteLine(i);
            });
            Console.WriteLine("-------------------------------------------");
            for (int i = 0; i < 100; i++)
            {
                Console.WriteLine(i);
            }
        }
        #endregion

        #region demo5
        /// <summary>
        /// Parallel.ForEach
        /// </summary>
        private static void demo5()
        {
            List<string> myList = new List<string>();
            // Parallel.ForEach(myList, (p) => { });
            Parallel.ForEach("Hello, world", (p) => {
                Console.WriteLine(p.ToString());
            });
        }
        #endregion

        #region demo6
        /// <summary>
        /// 中途退出循环
        /// </summary>
        private static void demo6()
        {
            ConcurrentBag<int> bag = new ConcurrentBag<int>(); // 线程安全的无序集合
            Stopwatch stopwatch = new Stopwatch();
            Console.WriteLine("Parallel:");
            stopwatch.Start();
            Parallel.For(0, 1000, (i, state) => {
                if (bag.Count == 300)
                {
                    state.Break();
                    // state.Stop();
                    return;
                }
                bag.Add(i);
            });
            stopwatch.Stop();
            Console.WriteLine("Parallel cost:" + stopwatch.ElapsedMilliseconds + " milliseconds," + "Bag Count:" + bag.Count);
        }
        #endregion

        #region demo7
        /// <summary>
        /// 异常处理
        /// </summary>
        private static void demo7()
        {
            Stopwatch stopwatch = new Stopwatch();
            Console.WriteLine("Parallel:");
            stopwatch.Start();
            try
            {
                Parallel.Invoke(RunThree, RunFour);
            }
            catch (AggregateException aex)
            {
                foreach (var ex in aex.InnerExceptions)
                {
                    Console.WriteLine(ex.Message);
                }
            }
            stopwatch.Stop();
            Console.WriteLine("Parallel cost:" + stopwatch.ElapsedMilliseconds + " milliseconds");
        }

        private static void RunThree()
        {
            Thread.Sleep(2000);
            Console.WriteLine("RunThree sleep 2 seconds");
            throw new Exception("Exception in RunThree");
        }

        private static void RunFour()
        {
            Thread.Sleep(3000);
            Console.WriteLine("RunFour sleep 3 seconds");
            throw new Exception("Exception in RunFour");
        }
        #endregion
    }
}
